﻿#pragma once
#include <string>
#include <variant>

#ifdef _DEBUG
#include <stdexcept>
#endif

namespace cpp
{
    /// 定义操作状态枚举，包含两种可能的状态：操作成功（OK）和操作失败（Error）
    enum class ResultStatus { OK, Error };

    /// 结果类模板，设计用于封装函数执行的结果。参考 rust 编程语言标准库里的 result。 \n
    /// 可以是成功结果（Ok_Type）或错误信息（Err_Type，默认为std::string，一个描述性字符串）。
    /// @code
    /// 一个可能失败的函数，返回Result类型
    /// cpp::Result<float> divide(int a, int b){
    ///     if (b == 0)
    ///         return cpp::Result<float>::Err("Division by zero");
    ///     return cpp::Result<float>::Ok(static_cast<float>(a) / static_cast<float>(b));
    /// }
    /// int main(){
    ///     auto result = divide(10, 0);
    ///     if (result) // 等价 if (result.isOk())
    ///         std::cout << "Result: " << result.unwrap() << std::endl;
    ///     else
    ///         std::cout << "Error: " << result.unwrap_err() << std::endl;
    ///     return 0;
    /// }
    /// @endcode
    template<typename OK_Type = std::nullptr_t, typename Err_Type = std::string>
    class Result
    {
    public:
        /// 静态工厂方法，用于创建表示成功的Result实例，接受一个成功值并将其存储
        static Result Ok(OK_Type value = nullptr)
        {
            return Result{ResultStatus::OK, std::move(value)};
        }

        /// 静态工厂方法，用于创建表示失败的Result实例，接受一个错误描述信息
        static Result Err(Err_Type error)
        {
            return Result{ResultStatus::Error, std::move(error)};
        }

        /// 检查此Result实例是否表示一个成功的操作
        bool isOK() const
        {
            return status == ResultStatus::OK;
        }
#ifdef _DEBUG
        template<typename U = OK_Type>
        std::enable_if_t<std::is_same_v<U, OK_Type>, U&> unwrap_Debug(const char* source_file, int source_line) &
        {
            if (isOK() == false)
                throw std::runtime_error{
                    std::string{"Result is error, unwrap exception. at: "}
                    .append(source_file).append(":").append(std::to_string(source_line))
                };
            return std::get<OK_Type>(storage);
        }

        /// 提供对成功结果的直接访问，调用前请先使用 isOK() 进行判断，只能通过左值对象调用。
        /// 采用宏获取更多调试信息，且保持和 Release 模式一致的 API。
#define unwrap() unwrap_Debug(__FILE__, __LINE__)

#endif

#ifndef _DEBUG
        /// 提供对成功结果的直接访问，调用前请先使用 isOK() 进行判断，只能通过左值对象调用
        template<typename U = OK_Type>
        std::enable_if_t<std::is_same_v<U, OK_Type>, U&> unwrap() &
        {
            return std::get<OK_Type>(storage);
        }
#endif

        /// 获取错误信息的方法，调用前请先使用 isOK() 进行判断，当结果表示失败时使用
        const Err_Type& unwrap_err() const
        {
            return std::get<Err_Type>(storage);
        }

        operator bool() const
        {
            return isOK();
        }

    private:
        std::variant<OK_Type, Err_Type> storage;
        ResultStatus status;

        explicit Result(const ResultStatus s, const std::variant<OK_Type, Err_Type>& val)
            : storage(val)
            , status(s) {}
    };
}
